home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / win_m_p / mews11.zip / EVAL.C < prev    next >
C/C++ Source or Header  |  1992-07-21  |  35KB  |  1,399 lines

  1. /*    EVAL.C: Expresion evaluation functions for
  2.         MicroEMACS
  3.  
  4.     written 1986 by Daniel Lawrence             */
  5.  
  6. #include    <stdio.h>
  7. #include    "estruct.h"
  8. #include    "eproto.h"
  9. #include    "edef.h"
  10. #include    "elang.h"
  11. #include    "evar.h"
  12.  
  13. PASCAL NEAR varinit()    /* initialize the user variable list */
  14.  
  15. {
  16.     register int i;
  17.  
  18.     for (i=0; i < MAXVARS; i++)
  19.         uv[i].u_name[0] = 0;
  20. }
  21.  
  22. PASCAL NEAR varclean()    /* initialize the user variable list */
  23.  
  24. {
  25.     register int i;
  26.  
  27.     for (i=0; i < MAXVARS; i++)
  28.         if (uv[i].u_name[0] != 0)
  29.             free(uv[i].u_value);
  30. }
  31.  
  32. char *PASCAL NEAR gtfun(fname)    /* evaluate a function */
  33.  
  34. char *fname;        /* name of function to evaluate */
  35.  
  36. {
  37.     register int fnum;        /* index to function to eval */
  38.     register int arg;        /* value of some arguments */
  39.     char arg1[NSTRING];        /* value of first argument */
  40.     char arg2[NSTRING];        /* value of second argument */
  41.     char arg3[NSTRING];        /* value of third argument */
  42.     static char result[2 * NSTRING];    /* string result */
  43. #if    ENVFUNC
  44.     char *getenv();         /* get environment string */
  45. #endif
  46.  
  47.     /* look the function up in the function table */
  48.     fname[3] = 0;    /* only first 3 chars significant */
  49.     mklower(fname); /* and let it be upper or lower case */
  50.     fnum = binary(fname, funval, NFUNCS);
  51.  
  52.     /* return errorm on a bad reference */
  53.     if (fnum == -1)
  54.         return(errorm);
  55.  
  56.     /* if needed, retrieve the first argument */
  57.     if (funcs[fnum].f_type >= MONAMIC) {
  58.         if (macarg(arg1) != TRUE)
  59.             return(errorm);
  60.  
  61.         /* if needed, retrieve the second argument */
  62.         if (funcs[fnum].f_type >= DYNAMIC) {
  63.             if (macarg(arg2) != TRUE)
  64.                 return(errorm);
  65.  
  66.             /* if needed, retrieve the third argument */
  67.             if (funcs[fnum].f_type >= TRINAMIC)
  68.                 if (macarg(arg3) != TRUE)
  69.                     return(errorm);
  70.         }
  71.     }
  72.  
  73.  
  74.     /* and now evaluate it! */
  75.     switch (fnum) {
  76.         case UFADD:    return(int_asc(asc_int(arg1) + asc_int(arg2)));
  77.         case UFSUB:    return(int_asc(asc_int(arg1) - asc_int(arg2)));
  78.         case UFTIMES:    return(int_asc(asc_int(arg1) * asc_int(arg2)));
  79.         case UFDIV:    return(int_asc(asc_int(arg1) / asc_int(arg2)));
  80.         case UFMOD:    return(int_asc(asc_int(arg1) % asc_int(arg2)));
  81.         case UFNEG:    return(int_asc(-asc_int(arg1)));
  82.         case UFCAT:    strcpy(result, arg1);
  83.                 return(strcat(result, arg2));
  84.         case UFLEFT:    return(bytecopy(result, arg1, asc_int(arg2)));
  85.         case UFRIGHT:    arg = asc_int(arg2);
  86.                 if (arg > strlen(arg1))
  87.                     arg = strlen(arg1);
  88.                 return(strcpy(result,
  89.                     &arg1[strlen(arg1) - arg]));
  90.         case UFMID:    arg = asc_int(arg2);
  91.                 if (arg > strlen(arg1))
  92.                     arg = strlen(arg1);
  93.                 return(bytecopy(result, &arg1[arg-1],
  94.                     asc_int(arg3)));
  95.         case UFNOT:    return(ltos(stol(arg1) == FALSE));
  96.         case UFEQUAL:    return(ltos(asc_int(arg1) == asc_int(arg2)));
  97.         case UFLESS:    return(ltos(asc_int(arg1) < asc_int(arg2)));
  98.         case UFGREATER: return(ltos(asc_int(arg1) > asc_int(arg2)));
  99.         case UFGROUP:
  100.                 if ((arg = asc_int(arg1)) < 0 || arg >= MAXGROUPS)
  101.                     return(bytecopy(result, errorm, NSTRING * 2));
  102.                     
  103. #if    MAGIC
  104.                 return(bytecopy(result, fixnull(grpmatch[arg]),
  105.                      NSTRING * 2));
  106. #else
  107.                 if (arg == 0)
  108.                     bytecopy(result, patmatch, NSTRING * 2);
  109.                 else
  110.                     result[0] = '\0';
  111.                 return(result);
  112. #endif
  113.         case UFSEQUAL:    return(ltos(strcmp(arg1, arg2) == 0));
  114.         case UFSLESS:    return(ltos(strcmp(arg1, arg2) < 0));
  115.         case UFSGREAT:    return(ltos(strcmp(arg1, arg2) > 0));
  116.         case UFIND:    return(strcpy(result, fixnull(getval(arg1))));
  117.         case UFAND:    return(ltos(stol(arg1) && stol(arg2)));
  118.         case UFOR:    return(ltos(stol(arg1) || stol(arg2)));
  119.         case UFLENGTH:    return(int_asc(strlen(arg1)));
  120.         case UFUPPER:    return(mkupper(arg1));
  121.         case UFLOWER:    return(mklower(arg1));
  122.         case UFTRUTH:    return(ltos(asc_int(arg1) == 42));
  123.         case UFASCII:    return(int_asc((int)arg1[0]));
  124.         case UFCHR:    result[0] = asc_int(arg1);
  125.                 result[1] = 0;
  126.                 return(result);
  127.         case UFGTCMD:    cmdstr(getcmd(), result);
  128.                 return(result);
  129.         case UFGTKEY:    result[0] = tgetc();
  130.                 result[1] = 0;
  131.                 return(result);
  132.         case UFRND:    return(int_asc((ernd() % absv(asc_int(arg1))) + 1));
  133.         case UFABS:    return(int_asc(absv(asc_int(arg1))));
  134.         case UFSINDEX:    return(int_asc(sindex(arg1, arg2)));
  135.         case UFENV:
  136. #if    ENVFUNC
  137.                 return(fixnull(getenv(arg1)));
  138. #else
  139.                 return("");
  140. #endif
  141.         case UFBIND:    return(transbind(arg1));
  142.         case UFEXIST:    return(ltos(fexist(arg1)));
  143.         case UFFIND:
  144.                 return(fixnull(flook(arg1, TRUE)));
  145.         case UFBAND:    return(int_asc(asc_int(arg1) & asc_int(arg2)));
  146.         case UFBOR:    return(int_asc(asc_int(arg1) | asc_int(arg2)));
  147.         case UFBXOR:    return(int_asc(asc_int(arg1) ^ asc_int(arg2)));
  148.         case UFBNOT:    return(int_asc(~asc_int(arg1)));
  149.         case UFXLATE:    return(xlat(arg1, arg2, arg3));
  150.         case UFTRIM:    return(trimstr(arg1));
  151.         case UFSLOWER:    return(setlower(arg1, arg2), "");
  152.         case UFSUPPER:    return(setupper(arg1, arg2), "");
  153.          case UFISNUM:    return(ltos(is_num(arg1)));
  154.     }
  155.  
  156.     meexit(-11);    /* never should get here */
  157. }
  158.  
  159. char *PASCAL NEAR gtusr(vname)    /* look up a user var's value */
  160.  
  161. char *vname;        /* name of user variable to fetch */
  162.  
  163. {
  164.     register int vnum;    /* ordinal number of user var */
  165.     register char *vptr;    /* temp pointer to function value */
  166.  
  167.     /* limit comparisons to significant length */
  168.     if (strlen(vname) >= NVSIZE)    /* "%" counts, but is not passed */
  169.         vname[NVSIZE-1] = '\0';
  170.  
  171.     /* scan the list looking for the user var name */
  172.     for (vnum = 0; vnum < MAXVARS; vnum++) {
  173.         if (uv[vnum].u_name[0] == 0)
  174.             return(errorm);
  175.         if (strcmp(vname, uv[vnum].u_name) == 0) {
  176.             vptr = uv[vnum].u_value;
  177.             if (vptr)
  178.                 return(vptr);
  179.             else
  180.                 return(errorm);
  181.         }
  182.     }
  183.  
  184.     /* return errorm if we run off the end */
  185.     return(errorm);
  186. }
  187.  
  188. char *PASCAL NEAR funval(i)
  189.  
  190. int i;
  191.  
  192. {
  193.     return(funcs[i].f_name);
  194. }
  195.  
  196. char *PASCAL NEAR envval(i)
  197.  
  198. int i;
  199.  
  200. {
  201.     return(envars[i]);
  202. }
  203.  
  204. PASCAL NEAR binary(key, tval, tlength)
  205.  
  206. char *key;        /* key string to look for */
  207. char *(PASCAL NEAR *tval)();    /* ptr to function to fetch table value with */
  208. int tlength;        /* length of table to search */
  209.  
  210. {
  211.     int l, u;    /* lower and upper limits of binary search */
  212.     int i;        /* current search index */
  213.     int cresult;    /* result of comparison */
  214.  
  215.     /* set current search limit as entire list */
  216.     l = 0;
  217.     u = tlength - 1;
  218.  
  219.     /* get the midpoint! */
  220.     while (u >= l) {
  221.         i = (l + u) >> 1;
  222.  
  223.         /* do the comparison */
  224.         cresult = strcmp(key, (*tval)(i));
  225.         if (cresult == 0)
  226.             return(i);
  227.         if (cresult < 0)
  228.             u = i - 1;
  229.         else
  230.             l = i + 1;
  231.     }
  232.     return(-1);
  233. }
  234.  
  235. char *PASCAL NEAR gtenv(vname)
  236.  
  237. char *vname;        /* name of environment variable to retrieve */
  238.  
  239. {
  240.     register int vnum;    /* ordinal number of var refrenced */
  241.     static char result[2 * NSTRING];    /* string result */
  242.  
  243.     /* scan the list, looking for the referenced name */
  244.     vnum = binary(vname, envval, NEVARS);
  245.  
  246.     /* return errorm on a bad reference */
  247.     if (vnum == -1)
  248.         return(errorm);
  249.  
  250.     /* otherwise, fetch the appropriate value */
  251.     switch (vnum) {
  252.         case EVFILLCOL: return(int_asc(fillcol));
  253.         case EVPAGELEN: return(int_asc(term.t_nrow + 1));
  254.         case EVCURCOL:    return(int_asc(getccol(FALSE)));
  255.         case EVCURLINE: return(int_asc(getlinenum(curbp, curwp->w_dotp)));
  256.         case EVRAM:    return(int_asc((int)(envram / 1024l)));
  257.         case EVFLICKER: return(ltos(flickcode));
  258.         case EVCURWIDTH:return(int_asc(term.t_ncol));
  259.         case EVCBFLAGS: return(int_asc(curbp->b_flag));
  260.         case EVCBUFNAME:return(curbp->b_bname);
  261.         case EVCFNAME:    return(curbp->b_fname);
  262.         case EVSRES:    return(sres);
  263.         case EVDEBUG:    return(ltos(macbug));
  264.         case EVSTATUS:    return(ltos(cmdstatus));
  265.         case EVPALETTE: return(palstr);
  266.         case EVASAVE:    return(int_asc(gasave));
  267.         case EVACOUNT:    return(int_asc(gacount));
  268.         case EVLASTKEY: return(int_asc(lastkey));
  269.         case EVCURCHAR:
  270.             return(curwp->w_dotp->l_used ==
  271.                     curwp->w_doto ? int_asc('\r') :
  272.                 int_asc(lgetc(curwp->w_dotp, curwp->w_doto)));
  273.         case EVDISCMD:    return(ltos(discmd));
  274.         case EVVERSION: return(VERSION);
  275.         case EVPROGNAME:return(PROGNAME);
  276.         case EVLANG:    return(LANGUAGE);
  277.         case EVSEED:    return(int_asc(seed));
  278.         case EVDISINP:    return(ltos(disinp));
  279.         case EVWLINE:    return(int_asc(curwp->w_ntrows));
  280.         case EVCWLINE:    return(int_asc(getwpos()));
  281.         case EVTARGET:    saveflag = lastflag;
  282.                 return(int_asc(curgoal));
  283.         case EVSEARCH:    return(pat);
  284.         case EVTIME:    return(timeset());
  285.         case EVREPLACE: return(rpat);
  286.         case EVMATCH:    return(fixnull(patmatch));
  287.         case EVKILL:    return(getkill());
  288.         case EVREGION:    return(getreg(result));
  289.         case EVCMODE:    return(int_asc(curbp->b_mode));
  290.         case EVGMODE:    return(int_asc(gmode));
  291.         case EVTPAUSE:    return(int_asc(term.t_pause));
  292.         case EVPENDING:
  293. #if    TYPEAH || WINDOW_MSWIN
  294.                 return(ltos(typahead()));
  295. #else
  296.                 return(falsem);
  297. #endif
  298.         case EVLWIDTH:    return(int_asc(llength(curwp->w_dotp)));
  299.         case EVLINE:    return(getctext());
  300.         case EVGFLAGS:    return(int_asc(gflags));
  301.         case EVRVAL:    return(int_asc(rval));
  302.         case EVREADHK:    return(fixnull(getfname(&readhook)));
  303.         case EVWRAPHK:    return(fixnull(getfname(&wraphook)));
  304.         case EVCMDHK:    return(fixnull(getfname(&cmdhook)));
  305.         case EVXPOS:    return(int_asc(xpos));
  306.         case EVYPOS:    return(int_asc(ypos));
  307.         case EVSTERM:    cmdstr(sterm, result);
  308.                 return(result);
  309.         case EVMODEFLAG:return(ltos(modeflag));
  310.         case EVSSCROLL: return(ltos(sscroll));
  311.         case EVLASTMESG:return(lastmesg);
  312.         case EVHARDTAB: return(int_asc(tabsize));
  313.         case EVSOFTTAB: return(int_asc(stabsize));
  314.         case EVSSAVE:    return(ltos(ssave));
  315.         case EVFCOL:    return(int_asc(curwp->w_fcol));
  316.         case EVHSCROLL: return(ltos(hscroll));
  317.         case EVHJUMP:    return(int_asc(hjump));
  318.         case EVBUFHOOK: return(fixnull(getfname(&bufhook)));
  319.         case EVEXBHOOK: return(fixnull(getfname(&exbhook)));
  320.         case EVWRITEHK: return(fixnull(getfname(&writehook)));
  321.         case EVDIAGFLAG:return(ltos(diagflag));
  322.         case EVMSFLAG:    return(ltos(mouseflag));
  323.         case EVOCRYPT:    return(ltos(oldcrypt));
  324.         case EVSEARCHPNT:    return(int_asc(searchtype));
  325.         case EVDISPHIGH:return(ltos(disphigh));
  326.         case EVLTERM:    return(lterm);
  327.         case EVPARALEAD:return(paralead);
  328.         case EVFMTLEAD:    return(fmtlead);
  329.         case EVWCHARS:    return(getwlist(result));
  330.         case EVPOPFLAG: return(ltos(popflag));
  331.         case EVPOSFLAG: return(ltos(posflag));
  332.         case EVYANKFLAG:    return(ltos(yankflag));
  333.         case EVSCRNAME:    return(first_screen->s_screen_name);
  334.         case EVCURWIND: return(int_asc(getcwnum()));
  335.         case EVNUMWIND: return(int_asc(gettwnum()));
  336.         case EVORGCOL:    return(int_asc(term.t_colorg));
  337.         case EVORGROW:    return(int_asc(term.t_roworg));
  338.         case EVDESKCLR:    return(cname[deskcolor]);
  339.         case EVTIMEFLAG: return(ltos(timeflag));
  340.         case EVHSCRLBAR: return(ltos(hscrollbar));
  341.         case EVVSCRLBAR: return(ltos(vscrollbar));
  342.     }
  343.     meexit(-12);    /* again, we should never get here */
  344. }
  345.  
  346. char *PASCAL NEAR fixnull(s)    /* Don't return NULL pointers! */
  347.  
  348. char *s;
  349.  
  350. {
  351.     if (s == NULL)
  352.         return("");
  353.     else
  354.         return(s);
  355. }
  356.  
  357. /* return some of the contents of the kill buffer */
  358.  
  359. char *PASCAL NEAR getkill()
  360.  
  361. {
  362.     register int size;    /* max number of chars left to return */
  363.     register char *sp;    /* ptr into KILL block data chunk */
  364.     register char *vp;    /* ptr into return value */
  365.     KILL *kptr;        /* ptr to the current KILL block */
  366.     int counter;        /* index into data chunk */
  367.     static char value[NSTRING];    /* temp buffer for value */
  368.  
  369.     /* no kill buffer....just a null string */
  370.     if (kbufh[kill_index] == (KILL *)NULL) {
  371.         value[0] = 0;
  372.         return(value);
  373.     }
  374.  
  375.     /* set up the output buffer */
  376.     vp = value;
  377.     size = NSTRING - 1;
  378.  
  379.     /* backed up characters? */
  380.     if (kskip[kill_index] > 0) {
  381.         kptr = kbufh[kill_index];
  382.         sp = &(kptr->d_chunk[kskip[kill_index]]);
  383.         counter = kskip[kill_index];
  384.         while (counter++ < KBLOCK) {
  385.             *vp++ = *sp++;
  386.             if (--size == 0) {
  387.                 *vp = 0;
  388.                 return(value);
  389.             }
  390.         }
  391.         kptr = kptr->d_next;
  392.     } else {
  393.         kptr = kbufh[kill_index];
  394.     }
  395.  
  396.     if (kptr != (KILL *)NULL) {
  397.         while (kptr != kbufp[kill_index]) {
  398.             sp = kptr->d_chunk;
  399.             for (counter = 0; counter < KBLOCK; counter++) {
  400.                 *vp++ = *sp++;
  401.                 if (--size == 0) {
  402.                     *vp = 0;
  403.                     return(value);
  404.                 }
  405.             }
  406.             kptr = kptr->d_next;
  407.         }
  408.         counter = kused[kill_index];
  409.         sp = kptr->d_chunk;
  410.         while (counter--) {
  411.             *vp++ = *sp++;
  412.             if (--size == 0) {
  413.                 *vp = 0;
  414.                 return(value);
  415.             }
  416.         }
  417.     }
  418.     
  419.     /* and return the constructed value */
  420.     *vp = 0;
  421.     return(value);
  422. }
  423.  
  424. char *PASCAL NEAR trimstr(s)    /* trim whitespace off the end of a string */
  425.  
  426. char *s;    /* string to trim */
  427.  
  428. {
  429.     char *sp;    /* backward index */
  430.  
  431.     sp = s + strlen(s) - 1;
  432.     while ((sp >= s) && (*sp == ' ' || *sp == '\t'))
  433.         --sp;
  434.     *(sp+1) = 0;
  435.     return(s);
  436. }
  437.  
  438. int PASCAL NEAR setvar(f, n)        /* set a variable */
  439.  
  440. int f;        /* default flag */
  441. int n;        /* numeric arg (can overide prompted value) */
  442.  
  443. {
  444.     register int status;    /* status return */
  445.     VDESC vd;        /* variable num/type */
  446.     char var[NVSIZE+1];    /* name of variable to fetch */
  447.     char value[NSTRING];    /* value to set variable to */
  448.  
  449.     /* first get the variable to set.. */
  450.     if (clexec == FALSE) {
  451.         status = mlreply(TEXT51, &var[0], NVSIZE+1);
  452. /*                 "Variable to set: " */
  453.         if (status != TRUE)
  454.             return(status);
  455.     } else {    /* macro line argument */
  456.         /* grab token and skip it */
  457.         execstr = token(execstr, var, NVSIZE + 1);
  458.     }
  459.  
  460.     /* check the legality and find the var */
  461.     findvar(var, &vd, NVSIZE + 1);
  462.         
  463.     /* if its not legal....bitch */
  464.     if (vd.v_type == -1) {
  465.         mlwrite(TEXT52, var);
  466. /*            "%%No such variable as '%s'" */
  467.         return(FALSE);
  468.     }
  469.  
  470.     /* get the value for that variable */
  471.     if (f == TRUE)
  472.         strcpy(value, int_asc(n));
  473.     else {
  474.         status = mlreply(TEXT53, &value[0], NSTRING);
  475. /*                 "Value: " */
  476.         if (status == ABORT)
  477.             return(status);
  478.     }
  479.  
  480.     /* and set the appropriate value */
  481.     status = svar(&vd, value);
  482.  
  483. #if    DEBUGM
  484.     /* if $debug == TRUE, every assignment will echo a statment to
  485.        that effect here. */
  486.         
  487.     if (macbug && (strcmp(var, "%track") != 0)) {
  488.         strcpy(outline, "(((");
  489.  
  490.         strcat(outline, var);
  491.         strcat(outline, " <- ");
  492.  
  493.         /* and lastly the value we tried to assign */
  494.         strcat(outline, value);
  495.         strcat(outline, ")))");
  496.  
  497.         /* expand '%' to "%%" so mlwrite wont bitch */
  498.         makelit(outline);
  499.  
  500.         /* write out the debug line */
  501.         mlforce(outline);
  502.         update(TRUE);
  503.  
  504.         /* and get the keystroke to hold the output */
  505.         if (getkey() == abortc) {
  506.             mlforce(TEXT54);
  507. /*                "[Macro aborted]" */
  508.             status = FALSE;
  509.         }
  510.     }
  511. #endif
  512.  
  513.     /* and return it */
  514.     return(status);
  515. }
  516.  
  517. PASCAL NEAR findvar(var, vd, size)    /* find a variables type and name */
  518.  
  519. char *var;    /* name of var to get */
  520. VDESC *vd;    /* structure to hold type and ptr */
  521. int size;    /* size of var array */
  522.  
  523. {
  524.     register int vnum;    /* subscript in varable arrays */
  525.     register int vtype;    /* type to return */
  526.  
  527. fvar:    vtype = -1;
  528.     switch (var[0]) {
  529.  
  530.         case '$': /* check for legal enviromnent var */
  531.             for (vnum = 0; vnum < NEVARS; vnum++)
  532.                 if (strcmp(&var[1], envars[vnum]) == 0) {
  533.                     vtype = TKENV;
  534.                     break;
  535.                 }
  536.             break;
  537.  
  538.         case '%': /* check for existing legal user variable */
  539.             for (vnum = 0; vnum < MAXVARS; vnum++)
  540.                 if (strcmp(&var[1], uv[vnum].u_name) == 0) {
  541.                     vtype = TKVAR;
  542.                     break;
  543.                 }
  544.             if (vnum < MAXVARS)
  545.                 break;
  546.  
  547.             /* create a new one??? */
  548.             for (vnum = 0; vnum < MAXVARS; vnum++)
  549.                 if (uv[vnum].u_name[0] == 0) {
  550.                     vtype = TKVAR;
  551.                     strcpy(uv[vnum].u_name, &var[1]);
  552.                     uv[vnum].u_value = NULL;
  553.                     break;
  554.                 }
  555.             break;
  556.  
  557.         case '&':    /* indirect operator? */
  558.             var[4] = 0;
  559.             if (strcmp(&var[1], "ind") == 0) {
  560.                 /* grab token, and eval it */
  561.                 execstr = token(execstr, var, size);
  562.                 strcpy(var, fixnull(getval(var)));
  563.                 goto fvar;
  564.             }
  565.     }
  566.  
  567.     /* return the results */
  568.     vd->v_num = vnum;
  569.     vd->v_type = vtype;
  570.     return;
  571. }
  572.  
  573. int PASCAL NEAR svar(var, value)    /* set a variable */
  574.  
  575. VDESC *var;    /* variable to set */
  576. char *value;    /* value to set to */
  577.  
  578. {
  579.     register int vnum;    /* ordinal number of var refrenced */
  580.     register int vtype;    /* type of variable to set */
  581.     register int status;    /* status return */
  582.     register int c;     /* translated character */
  583.     register char *sp;    /* scratch string pointer */
  584.  
  585.     /* simplify the vd structure (we are gonna look at it a lot) */
  586.     vnum = var->v_num;
  587.     vtype = var->v_type;
  588.  
  589.     /* and set the appropriate value */
  590.     status = TRUE;
  591.     switch (vtype) {
  592.     case TKVAR: /* set a user variable */
  593.         if (uv[vnum].u_value != NULL)
  594.             free(uv[vnum].u_value);
  595.         sp = malloc(strlen(value) + 1);
  596.         if (sp == NULL)
  597.             return(FALSE);
  598.         strcpy(sp, value);
  599.         uv[vnum].u_value = sp;
  600.         break;
  601.  
  602.     case TKENV: /* set an environment variable */
  603.         status = TRUE;    /* by default */
  604.         switch (vnum) {
  605.         case EVFILLCOL: fillcol = asc_int(value);
  606.                 break;
  607.         case EVPAGELEN: status = newsize(TRUE, asc_int(value));
  608.                 break;
  609.         case EVCURCOL:    status = setccol(asc_int(value));
  610.                 break;
  611.         case EVCURLINE: status = gotoline(TRUE, asc_int(value));
  612.                 break;
  613.         case EVRAM:    break;
  614.         case EVFLICKER: flickcode = stol(value);
  615.                 break;
  616.         case EVCURWIDTH:status = newwidth(TRUE, asc_int(value));
  617.                 break;
  618.         case EVCBFLAGS: curbp->b_flag = (curbp->b_flag & ~(BFCHG|BFINVS))
  619.                     | (asc_int(value) & (BFCHG|BFINVS));
  620.                 lchange(WFMODE);
  621.                 break;
  622.         case EVCBUFNAME:strcpy(curbp->b_bname, value);
  623.                 curwp->w_flag |= WFMODE;
  624.                 break;
  625.         case EVCFNAME:    strcpy(curbp->b_fname, value);
  626. #if     WINDOW_MSWIN
  627.                         fullpathname (curbp->b_fname, NFILEN);
  628. #endif
  629.                 curwp->w_flag |= WFMODE;
  630.                 break;
  631.         case EVSRES:    status = TTrez(value);
  632.                 break;
  633.         case EVDEBUG:    macbug = stol(value);
  634.                 break;
  635.         case EVSTATUS:    cmdstatus = stol(value);
  636.                 break;
  637.         case EVPALETTE: bytecopy(palstr, value, 48);
  638.                 spal(palstr);
  639.                 break;
  640.         case EVASAVE:    gasave = asc_int(value);
  641.                 break;
  642.         case EVACOUNT:    gacount = asc_int(value);
  643.                 break;
  644.         case EVLASTKEY: lastkey = asc_int(value);
  645.                 break;
  646.         case EVCURCHAR: ldelete(1L, FALSE);    /* delete 1 char */
  647.                 c = asc_int(value);
  648.                 if (c == '\r')
  649.                     lnewline();
  650.                 else
  651.                     linsert(1, (char)c);
  652.                 backchar(FALSE, 1);
  653.                 break;
  654.         case EVDISCMD:    discmd = stol(value);
  655.                 break;
  656.         case EVVERSION: break;
  657.         case EVPROGNAME:break;
  658.         case EVLANG:    break;
  659.         case EVSEED:    seed = asc_int(value);
  660.                 break;
  661.         case EVDISINP:    disinp = stol(value);
  662.                 break;
  663.         case EVWLINE:    status = resize(TRUE, asc_int(value));
  664.                 break;
  665.         case EVCWLINE:    status = forwline(TRUE,
  666.                         asc_int(value) - getwpos());
  667.                 break;
  668.         case EVTARGET:    curgoal = asc_int(value);
  669.                 thisflag = saveflag;
  670.                 break;
  671.         case EVSEARCH:    strcpy(pat, value);
  672.                 setjtable(); /* Set up fast search arrays  */
  673. #if    MAGIC
  674.                 mcclear();
  675. #endif
  676.                 break;
  677.         case EVTIME:    break;
  678.         case EVREPLACE: strcpy(rpat, value);
  679. #if    MAGIC
  680.                 rmcclear();
  681. #endif 
  682.                 break;
  683.         case EVMATCH:    break;
  684.         case EVKILL:    break;
  685.         case EVREGION:    break;
  686.         case EVCMODE:    curbp->b_mode = asc_int(value);
  687.                 curwp->w_flag |= WFMODE;
  688.                 break;
  689.         case EVGMODE:    gmode = asc_int(value);
  690.                 break;
  691.         case EVTPAUSE:    term.t_pause = asc_int(value);
  692.                 break;
  693.         case EVPENDING: break;
  694.         case EVLWIDTH:    break;
  695.         case EVLINE:    putctext(value);
  696.                 break;
  697.         case EVGFLAGS:    gflags = asc_int(value);
  698.                 break;
  699.         case EVRVAL:    break;
  700.         case EVREADHK:    setkey(&readhook, value);
  701.                 break;
  702.         case EVWRAPHK:    setkey(&wraphook, value);
  703.                 break;
  704.         case EVCMDHK:    setkey(&cmdhook, value);
  705.                 break;
  706.         case EVXPOS:    xpos = asc_int(value);
  707.                 break;
  708.         case EVYPOS:    ypos = asc_int(value);
  709.                 break;
  710.         case EVSTERM:    sterm = stock(value);
  711.                 break;
  712.         case EVMODEFLAG:modeflag = stol(value);
  713.                 upwind();
  714.                 break;
  715.         case EVSSCROLL: sscroll = stol(value);
  716.                 break;
  717.         case EVLASTMESG:strcpy(lastmesg, value);
  718.                 break;
  719.         case EVHARDTAB: tabsize = asc_int(value);
  720.                 upwind();
  721.                 break;
  722.         case EVSOFTTAB: stabsize = asc_int(value);
  723.                 upwind();
  724.                 break;
  725.         case EVSSAVE:    ssave = stol(value);
  726.                 break;
  727.         case EVFCOL:    curwp->w_fcol = asc_int(value);
  728.                 if (curwp->w_fcol < 0)
  729.                     curwp->w_fcol = 0;
  730.                 curwp->w_flag |= WFHARD | WFMODE;
  731.                 break;
  732.         case EVHSCROLL: hscroll = stol(value);
  733.                 lbound = 0;
  734.                 break;
  735.         case EVHJUMP:    hjump = asc_int(value);
  736.                 if (hjump < 1)
  737.                     hjump = 1;
  738.                 if (hjump > term.t_ncol - 1)
  739.                     hjump = term.t_ncol - 1;
  740.                 break;
  741.         case EVBUFHOOK: setkey(&bufhook, value);
  742.                 break;
  743.         case EVEXBHOOK: setkey(&exbhook, value);
  744.                 break;
  745.         case EVWRITEHK: setkey(&writehook, value);
  746.                 break;
  747.         case EVDIAGFLAG:diagflag = stol(value);
  748.                 break;
  749.         case EVMSFLAG:    mouseflag = stol(value);
  750.                 break;
  751.         case EVOCRYPT:    oldcrypt = stol(value);
  752.                 break;
  753.         case EVSEARCHPNT:    searchtype = asc_int(value);
  754.                 if (searchtype < SRNORM  || searchtype > SREND)
  755.                     searchtype = SRNORM;
  756.                 break;
  757.         case EVDISPHIGH:
  758.                 c = disphigh;
  759.                 disphigh = stol(value);
  760.                 if (c != disphigh)
  761.                     upwind();
  762.                 break;
  763.         case EVLTERM:    bytecopy(lterm, value, NSTRING);
  764.                 break;
  765.         case EVPARALEAD:bytecopy(paralead, value, NSTRING);
  766.                 break;
  767.         case EVFMTLEAD:    bytecopy(fmtlead, value, NSTRING);
  768.                 break;
  769.         case EVWCHARS:    setwlist(value);
  770.                 break;
  771.         case EVPOPFLAG: popflag = stol(value);
  772.                 break;
  773.         case EVPOSFLAG: posflag = stol(value);
  774.                 upmode();
  775.                 break;
  776.         case EVYANKFLAG:    yankflag = stol(value);
  777.                 break;
  778.         case EVSCRNAME:    select_screen(lookup_screen(value), TRUE);
  779.                 break;
  780.         case EVCURWIND:    nextwind(TRUE, asc_int(value));
  781.                 break;
  782.         case EVNUMWIND:    break;
  783.         case EVORGCOL:    status = new_col_org(TRUE, asc_int(value));
  784.                 break;
  785.         case EVORGROW:    status = new_row_org(TRUE, asc_int(value));
  786.                 break;
  787.         case EVDESKCLR:    c = lookup_color(mkupper(value));
  788.                 if (c != -1) {
  789.                     deskcolor = c;
  790. #if    WINDOW_TEXT
  791.                     refresh_screen(first_screen);
  792. #endif
  793.                 }
  794.                 break;
  795.         case EVTIMEFLAG: timeflag = stol(value);
  796.                 upmode();
  797.                 break;
  798.         case EVHSCRLBAR: hscrollbar = stol(value);
  799.                 break;
  800.         case EVVSCRLBAR: vscrollbar = stol(value);
  801.                 break;
  802.         }
  803.         break;
  804.     }
  805.     return(status);
  806. }
  807.  
  808. /*    asc_int:    ascii string to integer......This is too
  809.         inconsistant to use the system's    */
  810.  
  811. int PASCAL NEAR asc_int(st)
  812.  
  813. char *st;
  814.  
  815. {
  816.     int result;    /* resulting number */
  817.     int sign;    /* sign of resulting number */
  818.     char c;     /* current char being examined */
  819.  
  820.     result = 0;
  821.     sign = 1;
  822.  
  823.     /* skip preceding whitespace */
  824.     while (*st == ' ' || *st == '\t')
  825.         ++st;
  826.  
  827.     /* check for sign */
  828.     if (*st == '-') {
  829.         sign = -1;
  830.         ++st;
  831.     }
  832.     if (*st == '+')
  833.         ++st;
  834.  
  835.     /* scan digits, build value */
  836.     while ((c = *st++))
  837.         if (c >= '0' && c <= '9')
  838.             result = result * 10 + c - '0';
  839.         else
  840.             break;
  841.  
  842.     return(result * sign);
  843. }
  844.  
  845. /*    int_asc:    integer to ascii string.......... This is too
  846.             inconsistant to use the system's    */
  847.  
  848. char *PASCAL NEAR int_asc(i)
  849.  
  850. int i;    /* integer to translate to a string */
  851.  
  852. {
  853.     register int digit;        /* current digit being used */
  854.     register char *sp;        /* pointer into result */
  855.     register int sign;        /* sign of resulting number */
  856.     static char result[INTWIDTH+1]; /* resulting string */
  857.  
  858.     /* record the sign...*/
  859.     sign = 1;
  860.     if (i < 0) {
  861.         sign = -1;
  862.         i = -i;
  863.     }
  864.  
  865.     /* and build the string (backwards!) */
  866.     sp = result + INTWIDTH;
  867.     *sp = 0;
  868.     do {
  869.         digit = i % 10;
  870.         *(--sp) = '0' + digit;    /* and install the new digit */
  871.         i = i / 10;
  872.     } while (i);
  873.  
  874.     /* and fix the sign */
  875.     if (sign == -1) {
  876.         *(--sp) = '-';    /* and install the minus sign */
  877.     }
  878.  
  879.     return(sp);
  880. }
  881.  
  882. int PASCAL NEAR gettyp(token)    /* find the type of a passed token */
  883.  
  884. char *token;    /* token to analyze */
  885.  
  886. {
  887.     register char c;    /* first char in token */
  888.  
  889.     /* grab the first char (this is all we need) */
  890.     c = *token;
  891.  
  892.     /* no blanks!!! */
  893.     if (c == 0)
  894.         return(TKNUL);
  895.  
  896.     /* a numeric literal? */
  897.     if (c >= '0' && c <= '9')
  898.         return(TKLIT);
  899.  
  900.     switch (c) {
  901.         case '"':    return(TKSTR);
  902.  
  903.         case '!':    return(TKDIR);
  904.         case '@':    return(TKARG);
  905.         case '#':    return(TKBUF);
  906.         case '$':    return(TKENV);
  907.         case '%':    return(TKVAR);
  908.         case '&':    return(TKFUN);
  909.         case '*':    return(TKLBL);
  910.  
  911.         default:    return(TKCMD);
  912.     }
  913. }
  914.  
  915. char *PASCAL NEAR getval(token) /* find the value of a token */
  916.  
  917. char *token;        /* token to evaluate */
  918.  
  919. {
  920.     register int status;    /* error return */
  921.     register BUFFER *bp;    /* temp buffer pointer */
  922.     register int blen;    /* length of buffer argument */
  923.     register int distmp;    /* temporary discmd flag */
  924.     static char buf[NSTRING];/* string buffer for some returns */
  925.  
  926.     switch (gettyp(token)) {
  927.         case TKNUL:    return("");
  928.  
  929.         case TKARG:    /* interactive argument */
  930.                 strcpy(token, fixnull(getval(&token[1])));
  931.                 distmp = discmd;    /* echo it always! */
  932.                 discmd = TRUE;
  933.                 status = getstring(token,
  934.                        buf, NSTRING, ctoec('\r'));
  935.                 discmd = distmp;
  936.                 if (status == ABORT)
  937.                     return(NULL);
  938.                 return(buf);
  939.  
  940.         case TKBUF:    /* buffer contents fetch */
  941.  
  942.                 /* grab the right buffer */
  943.                 strcpy(token, fixnull(getval(&token[1])));
  944.                 bp = bfind(token, FALSE, 0);
  945.                 if (bp == NULL)
  946.                     return(NULL);
  947.             
  948.                 /* if the buffer is displayed, get the window
  949.                    vars instead of the buffer vars */
  950.                 if (bp->b_nwnd > 0) {
  951.                     curbp->b_dotp = curwp->w_dotp;
  952.                     curbp->b_doto = curwp->w_doto;
  953.                 }
  954.  
  955.                 /* make sure we are not at the end */
  956.                 if (bp->b_linep == bp->b_dotp)
  957.                     return(NULL);
  958.             
  959.                 /* grab the line as an argument */
  960.                 blen = bp->b_dotp->l_used - bp->b_doto;
  961.                 if (blen > NSTRING)
  962.                     blen = NSTRING;
  963.                 bytecopy(buf, bp->b_dotp->l_text + bp->b_doto,
  964.                     blen);
  965.                 buf[blen] = 0;
  966.             
  967.                 /* and step the buffer's line ptr ahead a line */
  968.                 bp->b_dotp = bp->b_dotp->l_fp;
  969.                 bp->b_doto = 0;
  970.  
  971.                 /* if displayed buffer, reset window ptr vars*/
  972.                 if (bp->b_nwnd > 0) {
  973.                     curwp->w_dotp = curbp->b_dotp;
  974.                     curwp->w_doto = 0;
  975.                     curwp->w_flag |= WFMOVE;
  976.                 }
  977.  
  978.                 /* and return the spoils */
  979.                 return(buf);            
  980.  
  981.         case TKVAR:    return(gtusr(token+1));
  982.         case TKENV:    return(gtenv(token+1));
  983.         case TKFUN:    return(gtfun(token+1));
  984.         case TKDIR:    return(NULL);
  985.         case TKLBL:    return(NULL);
  986.         case TKLIT:    return(token);
  987.         case TKSTR:    return(token+1);
  988.         case TKCMD:    return(token);
  989.     }
  990. }
  991.  
  992. int PASCAL NEAR stol(val)    /* convert a string to a numeric logical */
  993.  
  994. char *val;    /* value to check for stol */
  995.  
  996. {
  997.     /* check for logical values */
  998.     if (val[0] == 'F')
  999.         return(FALSE);
  1000.     if (val[0] == 'T')
  1001.         return(TRUE);
  1002.  
  1003.     /* check for numeric truth (!= 0) */
  1004.     return((asc_int(val) != 0));
  1005. }
  1006.  
  1007. char *PASCAL NEAR ltos(val)    /* numeric logical to string logical */
  1008.  
  1009. int val;    /* value to translate */
  1010.  
  1011. {
  1012.     if (val)
  1013.         return(truem);
  1014.     else
  1015.         return(falsem);
  1016. }
  1017.  
  1018. char *PASCAL NEAR mkupper(str)    /* make a string upper case */
  1019.  
  1020. char *str;        /* string to upper case */
  1021.  
  1022. {
  1023.     char *sp;
  1024.  
  1025.     sp = str;
  1026.     while (*sp)
  1027.         uppercase(sp++);
  1028.     return(str);
  1029. }
  1030.  
  1031. char *PASCAL NEAR mklower(str)    /* make a string lower case */
  1032.  
  1033. char *str;        /* string to lower case */
  1034.  
  1035. {
  1036.     char *sp;
  1037.  
  1038.     sp = str;
  1039.     while (*sp)
  1040.         lowercase(sp++);
  1041.     return(str);
  1042. }
  1043.  
  1044. int PASCAL NEAR absv(x) /* take the absolute value of an integer */
  1045.  
  1046. int x;
  1047.  
  1048. {
  1049.     return(x < 0 ? -x : x);
  1050. }
  1051.  
  1052. int PASCAL NEAR ernd()    /* returns a random integer */
  1053.  
  1054. {
  1055.     seed = absv(seed * 1721 + 10007);
  1056.     return(seed);
  1057. }
  1058.  
  1059. int PASCAL NEAR sindex(source, pattern) /* find pattern within source */
  1060.  
  1061. char *source;    /* source string to search */
  1062. char *pattern;    /* string to look for */
  1063.  
  1064. {
  1065.     char *sp;    /* ptr to current position to scan */
  1066.     char *csp;    /* ptr to source string during comparison */
  1067.     char *cp;    /* ptr to place to check for equality */
  1068.  
  1069.     /* scanning through the source string */
  1070.     sp = source;
  1071.     while (*sp) {
  1072.         /* scan through the pattern */
  1073.         cp = pattern;
  1074.         csp = sp;
  1075.         while (*cp) {
  1076.             if (!eq(*cp, *csp))
  1077.                 break;
  1078.             ++cp;
  1079.             ++csp;
  1080.         }
  1081.  
  1082.         /* was it a match? */
  1083.         if (*cp == 0)
  1084.             return((int)(sp - source) + 1);
  1085.         ++sp;
  1086.     }
  1087.  
  1088.     /* no match at all.. */
  1089.     return(0);
  1090. }
  1091.  
  1092. /*    Filter a string through a translation table    */
  1093.  
  1094. char *PASCAL NEAR xlat(source, lookup, trans)
  1095.  
  1096. char *source;    /* string to filter */
  1097. char *lookup;    /* characters to translate */
  1098. char *trans;    /* resulting translated characters */
  1099.  
  1100. {
  1101.     register char *sp;    /* pointer into source table */
  1102.     register char *lp;    /* pointer into lookup table */
  1103.     register char *rp;    /* pointer into result */
  1104.     static char result[NSTRING];    /* temporary result */
  1105.  
  1106.     /* scan source string */
  1107.     sp = source;
  1108.     rp = result;
  1109.     while (*sp) {
  1110.         /* scan lookup table for a match */
  1111.         lp = lookup;
  1112.         while (*lp) {
  1113.             if (*sp == *lp) {
  1114.                 *rp++ = trans[lp - lookup];
  1115.                 goto xnext;
  1116.             }
  1117.             ++lp;
  1118.         }
  1119.  
  1120.         /* no match, copy in the source char untranslated */
  1121.         *rp++ = *sp;
  1122.  
  1123. xnext:        ++sp;
  1124.     }
  1125.  
  1126.     /* terminate and return the result */
  1127.     *rp = 0;
  1128.     return(result);
  1129. }
  1130.  
  1131. /*    setwlist:    Set an alternative list of character to be
  1132.             considered "in a word */
  1133.  
  1134. PASCAL NEAR setwlist(wclist)
  1135.  
  1136. char *wclist;    /* list of characters to consider "in a word" */
  1137.  
  1138. {
  1139.     register int index;
  1140.  
  1141.     /* if we are turning this facility off, just flag so */
  1142.     if (wclist == NULL || *wclist == 0) {
  1143.         wlflag = FALSE;
  1144.         return;
  1145.     }
  1146.  
  1147.     /* first clear the table */
  1148.     for (index = 0; index < 256; index++)
  1149.         wordlist[index] = FALSE;
  1150.  
  1151.     /* and for each character in the new value, set that element
  1152.        of the word character list */
  1153.     while (*wclist)
  1154.         wordlist[*wclist++] = TRUE;
  1155.     wlflag = TRUE;
  1156.     return;
  1157. }
  1158.  
  1159. /*    getwlist:    place in a buffer a list of characters
  1160.             considered "in a word"            */
  1161.  
  1162. char *PASCAL NEAR getwlist(buf)
  1163.  
  1164. char *buf;    /* buffer to place list of characters */
  1165.  
  1166. {
  1167.     register int index;
  1168.     register char *sp;
  1169.  
  1170.     /* if we are defaulting to a standard word char list... */
  1171.     if (wlflag == FALSE)
  1172.         return("");
  1173.  
  1174.     /* build the string of characters in the return buffer */
  1175.     sp = buf;
  1176.     for (index = 0; index < 256; index++)
  1177.         if (wordlist[index])
  1178.             *sp++ = index;
  1179.     *sp = 0;
  1180.     return(buf);
  1181. }
  1182.  
  1183. /*    is_num:    ascii string is integer......This is too
  1184.         inconsistant to use the system's    */
  1185.  
  1186. int PASCAL NEAR is_num(st)
  1187.  
  1188. char *st;
  1189.  
  1190. {
  1191.     int period_flag;    /* have we seen a period yet? */
  1192.  
  1193.     /* skip preceding whitespace */
  1194.     while (*st == ' ' || *st == '\t')
  1195.         ++st;
  1196.  
  1197.     /* check for sign */
  1198.     if ((*st == '-') || (*st == '+'))
  1199.         ++st;
  1200.  
  1201.     /* scan digits */
  1202.     period_flag = FALSE;
  1203.     while ((*st >= '0') && (*st <= '9') ||
  1204.            (*st == '.' && period_flag == FALSE)) {
  1205.         if (*st == '.')
  1206.             period_flag = TRUE;
  1207.         st++;
  1208.     }
  1209.  
  1210.     /* scan rest of line for just white space */
  1211.     while (*st) {
  1212.         if ((*st != '\t') && (*st != ' '))
  1213.             return(FALSE);
  1214.         st++;
  1215.     }
  1216.     return(TRUE);
  1217. }
  1218.  
  1219. #if    DEBUGM
  1220. int PASCAL NEAR dispvar(f, n)        /* display a variable's value */
  1221.  
  1222. int f;        /* default flag */
  1223. int n;        /* numeric arg (can overide prompted value) */
  1224.  
  1225. {
  1226.     register int status;    /* status return */
  1227.     VDESC vd;        /* variable num/type */
  1228.     char var[NVSIZE+1];    /* name of variable to fetch */
  1229.  
  1230.     /* first get the variable to display.. */
  1231.     if (clexec == FALSE) {
  1232.         status = mlreply(TEXT55, &var[0], NVSIZE+1);
  1233. /*                 "Variable to display: " */
  1234.         if (status != TRUE)
  1235.             return(status);
  1236.     } else {    /* macro line argument */
  1237.         /* grab token and skip it */
  1238.         execstr = token(execstr, var, NVSIZE + 1);
  1239.     }
  1240.  
  1241.     /* check the legality and find the var */
  1242.     findvar(var, &vd, NVSIZE + 1);
  1243.         
  1244.     /* if its not legal....bitch */
  1245.     if (vd.v_type == -1) {
  1246.         mlwrite(TEXT52, var);
  1247. /*            "%%No such variable as '%s'" */
  1248.         return(FALSE);
  1249.     }
  1250.  
  1251.     /* and display the value */
  1252.     strcpy(outline, var);
  1253.     strcat(outline, " = ");
  1254.  
  1255.     /* and lastly the current value */
  1256.     strcat(outline, fixnull(getval(var)));
  1257.  
  1258.     /* expand '%' to "%%" so mlwrite wont bitch */
  1259.     makelit(outline);
  1260.  
  1261.     /* write out the result */
  1262.     mlforce(outline);
  1263.     update(TRUE);
  1264.  
  1265.     /* and return */
  1266.     return(TRUE);
  1267. }
  1268.  
  1269. /*    describe-variables    Bring up a fake buffer and list the contents
  1270.                 of all the environment variables
  1271. */
  1272.  
  1273. PASCAL NEAR desvars(f, n)
  1274.  
  1275. int f,n;    /* prefix flag and argument */
  1276.  
  1277. {
  1278.     register WINDOW *wp;    /* scanning pointer to windows */
  1279.     register BUFFER *varbuf;/* buffer to put variable list into */
  1280.     register int uindex;    /* index into uvar table */
  1281.     char outseq[256];    /* output buffer for keystroke sequence */
  1282.  
  1283.     /* and get a buffer for it */
  1284.     varbuf = bfind(TEXT56, TRUE, BFINVS);
  1285. /*           "Variable list" */
  1286.     if (varbuf == NULL || bclear(varbuf) == FALSE) {
  1287.         mlwrite(TEXT57);
  1288. /*            "Can not display variable list" */
  1289.         return(FALSE);
  1290.     }
  1291.  
  1292.     /* let us know this is in progress */
  1293.     mlwrite(TEXT58);
  1294. /*        "[Building variable list]" */
  1295.  
  1296.     /* build the environment variable list */
  1297.     for (uindex = 0; uindex < NEVARS; uindex++) {
  1298.  
  1299.         /* add in the environment variable name */
  1300.         strcpy(outseq, "$");
  1301.         strcat(outseq, envars[uindex]);
  1302.         pad(outseq, 14);
  1303.             
  1304.         /* add in the value */
  1305.         strcat(outseq, gtenv(envars[uindex]));
  1306.  
  1307.         /* and add it as a line into the buffer */
  1308.         if (addline(varbuf, outseq) != TRUE)
  1309.             return(FALSE);
  1310.     }
  1311.  
  1312.     if (addline(varbuf, "") != TRUE)
  1313.         return(FALSE);
  1314.  
  1315.     /* build the user variable list */
  1316.     for (uindex = 0; uindex < MAXVARS; uindex++) {
  1317.         if (uv[uindex].u_name[0] == 0)
  1318.             break;
  1319.  
  1320.         /* add in the user variable name */
  1321.         strcpy(outseq, "%");
  1322.         strcat(outseq, uv[uindex].u_name);
  1323.         pad(outseq, 14);
  1324.             
  1325.         /* add in the value */
  1326.         strcat(outseq, uv[uindex].u_value);
  1327.  
  1328.         /* and add it as a line into the buffer */
  1329.         if (addline(varbuf, outseq) != TRUE)
  1330.             return(FALSE);
  1331.     }
  1332.  
  1333.     /* display the list */
  1334.     wpopup(varbuf);
  1335.     mlerase();    /* clear the mode line */
  1336.     return(TRUE);
  1337. }
  1338.  
  1339. /*    describe-functions    Bring up a fake buffer and list the
  1340.                 names of all the functions
  1341. */
  1342.  
  1343. PASCAL NEAR desfunc(f, n)
  1344.  
  1345. int f,n;    /* prefix flag and argument */
  1346.  
  1347. {
  1348.     register WINDOW *wp;    /* scanning pointer to windows */
  1349.     register BUFFER *fncbuf;/* buffer to put function list into */
  1350.     register int uindex;    /* index into funcs table */
  1351.     char outseq[80];    /* output buffer for keystroke sequence */
  1352.  
  1353.     /* get a buffer for the function list */
  1354.     fncbuf = bfind(TEXT211, TRUE, BFINVS);
  1355. /*           "Function list" */
  1356.     if (fncbuf == NULL || bclear(fncbuf) == FALSE) {
  1357.         mlwrite(TEXT212);
  1358. /*            "Can not display function list" */
  1359.         return(FALSE);
  1360.     }
  1361.  
  1362.     /* let us know this is in progress */
  1363.     mlwrite(TEXT213);
  1364. /*        "[Building function list]" */
  1365.  
  1366.     /* build the function list */
  1367.     for (uindex = 0; uindex < NFUNCS; uindex++) {
  1368.  
  1369.         /* add in the environment variable name */
  1370.         strcpy(outseq, "&");
  1371.         strcat(outseq, funcs[uindex].f_name);
  1372.  
  1373.         /* and add it as a line into the buffer */
  1374.         if (addline(fncbuf, outseq) != TRUE)
  1375.             return(FALSE);
  1376.     }
  1377.  
  1378.     if (addline(fncbuf, "") != TRUE)
  1379.         return(FALSE);
  1380.  
  1381.     /* display the list */
  1382.     wpopup(fncbuf);
  1383.     mlerase();    /* clear the mode line */
  1384.     return(TRUE);
  1385. }
  1386.  
  1387. pad(s, len)    /* pad a string to indicated length */
  1388.  
  1389. char *s;    /* string to add spaces to */
  1390. int len;    /* wanted length of string */
  1391.  
  1392. {
  1393.     while (strlen(s) < len) {
  1394.                 strcat(s, "          ");
  1395.         s[len] = 0;
  1396.     }
  1397. }
  1398. #endif
  1399.